using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Mbs.Modularity.AddIns;
using Mbs.Reflection;

namespace Mbs.Modularity
{

    public static class ModuleMeta
    {
        [Serializable]
        [DebuggerDisplay("Id={Id}, AssemblyFile={AssemblyFile},AddInFile={AddInFile},IsSystem={IsSystem}")]
        private class DefaultModuleMeta : IModuleMeta
        {
            public string Name
            {
                get
                {
                    if (AddIn != null && !string.IsNullOrEmpty(AddIn.Name)) return AddIn.Name;
                    return AssemblyName;
                }
            }

            public string Version { get; internal set; }
            public string AssemblyFile { get; set; }
            public string UpdateLocation { get; set; }
            public bool LazyLoad { get; set; }

            public IAddIn AddIn { get; private set; }

            public bool IsSystem { get; internal set; }

            internal string AddInFile;
            private Assembly _Assembly;
            private string AssemblyName;

            public DefaultModuleMeta()
            {
            }


            public DefaultModuleMeta(Assembly assembly)
            {
                Init(assembly);

            }

            private void Init(Assembly assembly)
            {
                if (assembly == null)
                    throw new ArgumentNullException("assembly");

                _Assembly = assembly;
                AssemblyFile = assembly.CodeBase.Replace("file:///", "").Replace('/', '\\');
                Version = assembly.GetName().Version.ToString();
                AssemblyName = assembly.GetName().Name;
            }

            public void LoadAddIn()
            {
                if (File.Exists(AddInFile))
                    AddIn = Mbs.Modularity.AddIns.AddIn.Load(AddInFile);
                else
                {
                    if (_Assembly == null)
                    {
                        var asm = Assembly.LoadFrom(AssemblyFile);
                        if (asm == null)
                            return;
                        Init(asm);
                    }

                    string resName = _Assembly.GetManifestResourceNames().FirstOrDefault((item) => item.Contains(".dll.AddIn"));
                    if (!string.IsNullOrEmpty(resName))
                        AddIn = Mbs.Modularity.AddIns.AddIn.Load(_Assembly.GetManifestResourceStream(resName));

                    if (AddIn == null)
                        AddIn = Mbs.Modularity.AddIns.AddIn.Load(_Assembly);

                }
            }

            public override string ToString()
            {
                return string.Format("Id[{0}],AssemblyFile[{1}]", Name, AssemblyFile);
            }

        }

        public static IModuleMeta Load(string assemblyFile, bool isLazyLoad)
        {
            var meta = new DefaultModuleMeta();
            meta.AssemblyFile = assemblyFile;
            meta.LazyLoad = isLazyLoad;

            CheckExtensionName(meta, ".dll");
            return meta;

        }

        public static IModuleMeta Load(Assembly assembly,bool isLazyLoad)
        {
            var meta = new DefaultModuleMeta(assembly);
            meta.LazyLoad = isLazyLoad;
            return meta;
        }

        internal static IModuleMeta LoadSystemModule()
        {
            var meta =new DefaultModuleMeta(Assembly.GetExecutingAssembly());
            meta.LazyLoad = false;
            meta.IsSystem = true;

            const string defaultConfig = @"AddIns\Mbs.AddIn";

            if (File.Exists(defaultConfig))
                meta.AddInFile = defaultConfig;
            else
            {
                var items = Directory.GetFiles(MbsEnvironment.ApplicationPath, "*.Mbs.AddIn");
                if (items != null && items.Length > 0)
                    meta.AddInFile = items[0];
            }

            if (File.Exists(meta.AddInFile))
            {
                meta.LoadAddIn();
            }

            return meta;
        }

        private static void CheckExtensionName(DefaultModuleMeta info, string extensionName)
        {
            if (!info.AssemblyFile.EndsWith(extensionName))
                info.AssemblyFile += extensionName;
            var assemblyFile = info.AssemblyFile;
            if (File.Exists(assemblyFile))
            {
                if (!assemblyFile.Contains(MbsEnvironment.AddInPathName))
                    info.AddInFile = MbsEnvironment.AddInPath + Path.GetFileName(assemblyFile) +MbsEnvironment.AddInExtensionName;
                else
                    info.AddInFile = Path.GetFileName(assemblyFile) + MbsEnvironment.AddInExtensionName;
            }
            else
            {
                assemblyFile = MbsEnvironment.AddInPath + assemblyFile;
                if (File.Exists(assemblyFile))
                {
                    info.AddInFile = MbsEnvironment.AddInPath + Path.GetFileName(assemblyFile) + MbsEnvironment.AddInExtensionName;
                    info.AssemblyFile = assemblyFile;
                }
            }
            

        }
    }
}
